#ifndef __SYLAR_TIMER_H__
#define __SYLAR_TIMER_H__

#include <memory>
#include <vector>
#include <set>
#include <shared_mutex>
#include <assert.h>
#include <functional>
#include <mutex>

namespace zsylar
{
class TimerManager;

class Timer : public std::enable_shared_from_this<Timer>
{
    // 友元类 TimerManager 可以访问 Timer 的私有成员和保护成员
    friend class TimerManager;
public:
    /**
     * @brief 从时间堆中删除当前定时器
     * @return 如果成功删除返回 true，否则返回 false
     */
    bool cancel();

    /**
     * @brief 刷新当前定时器的状态，更新其在时间堆中的位置
     * @return 如果成功刷新返回 true，否则返回 false
     */
    bool refresh();

    /**
     * @brief 重设定时器的超时时间
     * @param ms 新的超时时间，单位为毫秒
     * @param from_now 是否从当前时间开始计算新的超时时间
     * @return 如果成功重设返回 true，否则返回 false
     */
    bool reset(uint64_t ms, bool from_now);

private:
    /**
     * @brief 构造函数
     * @param ms 超时时间，单位为毫秒
     * @param cb 超时触发的回调函数
     * @param recurring 是否为循环定时器
     * @param manager 管理此定时器的 TimerManager 实例
     */
    Timer(uint64_t ms, std::function<void()> cb, bool recurring, TimerManager* manager); 

private:
    // 是否循环
    bool m_recurring = false;
    // 超时时间，单位为毫秒
    uint64_t m_ms = 0;
    // 绝对超时时间，使用系统时钟的时间点表示
    std::chrono::time_point<std::chrono::system_clock> m_next;
    // 超时触发的回调函数
    std::function<void()> m_cb;
    // 管理此timer的管理器
    TimerManager* m_manager = nullptr;   

private:
    /**
     * @brief 实现最小堆的比较函数，用于在时间堆中排序定时器
     */
    struct Comparator
    {
        bool operator()(const std::shared_ptr<Timer>& lhs, const std::shared_ptr<Timer>& rhs) const;
    };
};

class TimerManager
{
    friend class Timer;
public:
    TimerManager();
    virtual ~TimerManager();

    /**
     * @brief 添加一个定时器
     * @param ms 定时器的超时时间，单位为毫秒
     * @param cb 定时器触发时执行的回调函数
     * @param recurring 是否为循环定时器，默认为 false
     * @return 返回添加的定时器的智能指针
     */
    std::shared_ptr<Timer> addTimer(uint64_t ms, std::function<void()> cb, bool recurring = false);

    /**
     * @brief 添加一个带条件的定时器
     * @param ms 定时器的超时时间，单位为毫秒
     * @param cb 定时器触发时执行的回调函数
     * @param weak_cond 条件的弱指针，定时器只有在条件对象未被销毁时才会触发
     * @param recurring 是否为循环定时器，默认为 false
     * @return 返回添加的定时器的智能指针
     */
    std::shared_ptr<Timer> addConditionTimer(uint64_t ms, std::function<void()> cb,
        std::weak_ptr<void> weak_cond, bool recurring = false);

    // 拿到堆中最近的超时时间
    uint64_t getNextTimer();

    // 去除所有超时定时器的回调函数
    // 该函数会从定时器堆中找到所有已经超时的定时器，并将它们的回调函数存储到传入的 cbs 容器中
    // 用于批量处理超时事件，避免逐个检查定时器是否超时。
    void listExpiredCb(std::vector<std::function<void()>>& cbs);

    // 函数用于检查定时器堆中是否存在任何定时器
    // 可以用来快速判断是否需要处理定时器事件或是否可以跳过定时器相关逻辑
    bool hasTimer();

protected:
    // 当一个最早的定时器timer加入堆中 -> 调用该函数
    virtual void onTimerInsertedAtFront() {};

    // 添加定时器到堆中
    void addTimer(std::shared_ptr<Timer> timer);

private:
    // 当系统时间改变时 -> 调用该函数
    // 该函数用于更新定时器的绝对超时时间，通常在系统时间发生变化时调用
    bool detectClockRollover();

private:
    std::shared_mutex m_mutex; // 互斥锁，保护定时器堆的访问

    // 时间堆，存储所有定时器
    // m_timers 是一个使用 std::shared_ptr<Timer> 的最小堆，
    // 按照定时器的绝对超时时间排序, 这样可以快速找到下一个超时的定时器
    // Comparator 用于比较两个定时器的超时时间，以便在堆中正确排序
    // 该堆的实现依赖于 std::set 的有序特性
    // 通过使用 std::shared_ptr<Timer>，可以确保定时器在使用期间不会被销毁，
    // 直到所有对它的引用都被释放
    std::set<std::shared_ptr<Timer>, Timer::Comparator> m_timers;

    // 在下次 getNextTimer() 执行前 onTimerInsertedAtFront()
    // 是否已经被触发了 -> 在此过程中 onTimerInsertedAtFront()
    // 只执行一次，避免重复触发
    // 这个标志位用于优化性能，避免在每次获取下一个定时器时都调用 onTimerInsertedAtFront()
    // 当有新的定时器被添加到堆中时，如果这是堆中第一个定时器，
    // 则会触发 onTimerInsertedAtFront()
    // 以便进行必要的处理，比如更新内部状态或通知其他组件
    bool m_tickled = false; // 标志位，表示是否有定时器被触发

    // 上次检查系统时间是否回退的绝对时间
    std::chrono::time_point<std::chrono::system_clock> m_previousTime;
};

}

#endif
